######################################################################################
#
# This file was provided as part of the SharePoint Mystery Deployment package
# Created by Christopher Kimbell (http://sharepointmystery.com)
#
######################################################################################

# -----------------------------------------------------------------
# Adds a method to the object
# -----------------------------------------------------------------
function Add-Method($obj, $name, $body)
{
     $obj | Add-Member ScriptMethod $name $body
}
# -----------------------------------------------------------------
# Adds a property to the object
# -----------------------------------------------------------------
function Add-Property($obj, $name, $body)
{
     $obj | Add-Member -MemberType ScriptProperty -Name $name -Value $body  	 
}
# -----------------------------------------------------------------
# Writes a message signaling the start of an operation
# -----------------------------------------------------------------
function Write-Operation($message)
{
    Write-Host $message -ForegroundColor Green
}
# -----------------------------------------------------------------
# Appends the operation message with .
# -----------------------------------------------------------------
function Write-OperationProgress()
{
    Write-Host "." -ForegroundColor Green -NoNewline
}
# -----------------------------------------------------------------
# Writes a message signaling that an operation has already been done
# -----------------------------------------------------------------
function Write-OperationDone($message)
{
    Write-Host $message -ForegroundColor Cyan
}
# -----------------------------------------------------------------
# Terminates the deployment process with the specified message
# -----------------------------------------------------------------
function Terminate($message)
{
    #Write-Host $message -ForegroundColor Red
    #Stop-Transcript -ErrorAction "SilentlyContinue"
    $host.SetShouldExit(1)
	throw $message
    #exit
}
# -----------------------------------------------------------------
# Adds a solution to the solution store
# -----------------------------------------------------------------
function Add-Solution($name)
{
    $solution = Get-SPSolution | Where-Object {$_.Name -eq $name}
    $cd = Get-Location
    $lp = $cd.Path + "\" + $name
    
    if($solution -eq $null) 
    {
        Write-Operation "Adding Solution $($name)"
        $solution = Add-SPSolution -LiteralPath $lp
    }
    return $solution
}
# -----------------------------------------------------------------
# Waits for a solution timer job to complete
# -----------------------------------------------------------------
function Wait-Solution($name)
{
	do 
	{ 
		Write-OperationProgress
		Start-Sleep 2
	} 
	while ((Get-SPSolution $name).JobExists -eq $true)
    Start-Sleep 5 # fore safe measure
}
# -----------------------------------------------------------------
# Enables a timer job
# -----------------------------------------------------------------
function Enable-TimerJob($name)
{
    $job = Get-SPTimerJob | Where-Object {$_.Name.EndsWith($name) -eq $true}
    
    if($job -ne $null)
    {
        if($job.IsDisabled -eq $true)
        {
            $job.IsDisabled = $false
            $job.Update()
        }
    }
    else
    {
        Write-Warning "A timer job with the name $($name) was not found"
    }
}
# -----------------------------------------------------------------
# Disables a timer job
# -----------------------------------------------------------------
function Disable-TimerJob($name)
{
    $job = Get-SPTimerJob | Where-Object {$_.Name.EndsWith($name) -eq $true}
    
    if($job -ne $null)
    {
        if($job.IsDisabled -eq $false)
        {
            $job.IsDisabled = $true
            $job.Update()
        }
    }
    else
    {
        Write-Warning "A timer job with the name $($name) was not found"
    }
}
# -----------------------------------------------------------------
# Removes a service application
# -----------------------------------------------------------------
function Remove-ServiceApplication($name)
{
    $sa = Get-SPServiceApplication  | Where-Object {$_.DisplayName -eq $name}

    if($sa -ne $null)
    {
        Write-Operation "Removing $($sa.DisplayName)"
        Remove-SPServiceApplication -Identity $sa -Confirm:$false -RemoveData
    }
}

# -----------------------------------------------------------------
# Removes a service application proxy
# -----------------------------------------------------------------
function Remove-ServiceApplicationProxy($name)
{
    $sa = Get-SPServiceApplicationProxy  | Where-Object {$_.DisplayName -eq $name}

    if($sa -ne $null)
    {
        Write-Operation "Removing $($sa.DisplayName)"
        Remove-SPServiceApplicationProxy -Identity $sa -Confirm:$false
    }
}
# -----------------------------------------------------------------
# Adds a set of users to a group
# -----------------------------------------------------------------
function AddUsersToGroup($users, $group)
{ 
    if($group -eq $null)  { return }
        
    foreach ($login in $users) 
    {
        $user = Get-SPUser -Limit All -Web $group.ParentWeb -Group "$($group)" | Where {$_.DisplayName -eq "$($login)"}
        if($user -eq $null)
        {
            Write-Operation "Adding user $(login) to $($group.Name)"
            New-SPUser -UserAlias $login -Web $group.ParentWeb -Group $group
        }
    }
}  
# -----------------------------------------------------------------
# Adds a permission entry for a specific user on a server
# -----------------------------------------------------------------
function Grant-Permission($service, $login, $permission, $admin)
{
    Write-Operation "Giving $($login) $($permission) to $($service.Name)"
    
    $security = Get-SPServiceApplicationSecurity $service -Admin:$admin
    $principal = New-SPClaimsPrincipal -Identity $login -IdentityType WindowsSamAccountName

    Grant-SPObjectSecurity $security -Principal $principal -Rights $permission
    Set-SPServiceApplicationSecurity $service -ObjectSecurity $security -Admin:$admin
}
# -----------------------------------------------------------------
# Registers a Managed account
# -----------------------------------------------------------------
function Register-ManagedAccount($login)
{
	$ma = Get-SPManagedAccount | Where-Object {$_.UserName -eq $login} 
	if($ma -eq $null)  
	{  
		Write-Operation "Please provide the password for $($login)"
		$credentials = Get-Credential $login  
		$ma = New-SPManagedAccount -Credential $credentials
	}  
	return $ma
}
# -----------------------------------------------------------------
# Gets the password for a managed account
# -----------------------------------------------------------------
function Get-ManagedAccountPassword ($account)
{
	# based on code from:
	# http://blogs.msdn.com/b/besidethepoint/archive/2010/09/23/retrieve-the-password-for-an-spmanagedaccount.aspx

	## using Reflection, get the private m_Password field
	## this field contains an SPEncryptedString
	$type = [Microsoft.SharePoint.Administration.SPManagedAccount]
	$flags = [System.Reflection.BindingFlags] ( "NonPublic", "GetField", "Instance" )
	$estrPassword = $type.InvokeMember( "m_Password", $flags, $null, $account, $null )
	## use the SecureStringValue property of SPEncryptedString to return a SecureString of the password
	return $estrPassword.SecureStringValue
}

function Validate-NotEmpty($name, $value)
{
    if($value -eq "") 
    {
        Terminate "$($name) cannot be empty"
    }
}
function Validate-Range($name, $value, $min, $max)
{
    if($value -lt $min -or $value -gt $max)
    {
        Terminate "$($name) must be between $($min) and $($max)"
    }
}
function Validate-MemberOf($name, $value, $range)
{
    foreach($r in $range)
    {
        if($r -eq $value) { return }
    }
    Terminate "$($name) must be a member of $($range)"
}
function _d($obj)
{
	Write-Host "Debug" -ForegroundColor Magenta
	out-host -InputObject $obj
	return
}